import WebpackLicense from '@components/WebpackLicense';
import { ApiMeta } from '@components/ApiMeta';

<WebpackLicense from="https://webpack.docschina.org/configuration/experiments/#experimentslazycompilation" />

# LazyCompilation

<ApiMeta addedVersion="1.5.0" />

懒编译（Lazy Compilation）是一种优化技术，可以延迟模块的编译，直到它们被实际请求时才进行构建。**只有在真正访问到某个入口或模块时，才进行构建。**

开启懒编译，对提高多入口应用（MPA）或大型单页面应用（SPA）的 dev 启动性能会非常有帮助。

## lazyCompilation

- **类型：** `boolean | LazyCompilationOptions`
- **默认值：** `false`

```ts
type LazyCompilationOptions =
  | boolean
  | {
      /**
       * 为 entries 启用 lazy compilation
       * @default true
       */
      entries?: boolean;
      /**
       * 为 dynamic imports 启用 lazy compilation
       * @default true
       */
      imports?: boolean;
      /**
       * 指定哪些导入的模块应该被延迟编译
       */
      test?: RegExp | ((m: Module) => boolean);
      /**
       * 自定义客户端脚本路径
       */
      client?: string;
      /**
       * 自定义服务端路径
       */
      serverUrl?: string;
      /**
       * 自定义懒编译端点的前缀
       * @default "/lazy-compilation-using-"
       */
      prefix?: string;
    };
```

:::tip
参考 [指南](/guide/features/lazy-compilation) 来快速上手。
:::

如果你有二十个入口，当开启懒编译时，只有访问到的入口才会进行构建，或者如果项目中存在非常多的 `import()`，每一个 `import()` 所指向的模块都只有在被真正访问到时，才进行构建。

如果设置为 true，则默认会对入口模块以及 `import()` 指向的模块进行懒编译。你可以通过配置对象形式，来决定是否只对入口或只对 `import()` 生效。`entries` 决定是否对入口生效，`import()` 决定是否对 `import()` 生效。

```js title="rspack.config.mjs"
const isDev = process.env.NODE_ENV === 'development';

export default {
  // 仅在 dev 模式下开启
  lazyCompilation: isDev,
};
```

除此以外你还可以配置 `test` 来更细粒度控制对哪些模块进行懒编译。`test` 可以是一个正则表达式，只对该正则匹配到的模块进行懒编译，`test` 也可以是一个函数，函数的输入是 `Module` 类型，返回 `boolean` 类型，表示是否命中懒编译逻辑。

### lazyCompilation.client

- **类型：** `string`

用于覆盖默认 lazy compilation 的客户端运行时，如果你想要自定义客户端运行时的逻辑，可以通过该配置项来指定。

你可以参考默认实现：

- [web 环境运行时](https://github.com/web-infra-dev/rspack/blob/699229b9e7c33b7db7968c2f803f750e0367fe8a/packages/rspack/hot/lazy-compilation-web.js)
- [node 环境运行时](https://github.com/web-infra-dev/rspack/blob/699229b9e7c33b7db7968c2f803f750e0367fe8a/packages/rspack/hot/lazy-compilation-node.js)

```js title="rspack.config.mjs"
import path from 'path';

export default {
  lazyCompilation: {
    client: path.resolve('custom-client.js'),
  },
};
```

### lazyCompilation.serverUrl

- **类型：** `string`

告诉客户端需要请求的服务端路径，默认为空，在浏览器环境会找到页面所在的服务端路径，但在 Node 环境下需要显式指定具体的路径。

```js title="rspack.config.mjs"
export default {
  lazyCompilation: {
    serverUrl: 'http://localhost:3000',
  },
};
```

### lazyCompilation.prefix

- **类型：** `string`
- **默认值：** `'/lazy-compilation-using-'`

自定义懒编译请求前缀。默认情况下，懒编译中间件使用 `/lazy-compilation-using-` 前缀来处理请求。

```js title="rspack.config.mjs"
export default {
  lazyCompilation: {
    prefix: '/custom-lazy-endpoint-',
  },
};
```

### 排除 HMR client

如果你未使用 Rspack 的 dev server，而是使用自己的 server 作为开发服务器，一般会在 entry 配置中加入另外的 client 代码来开启 HMR 等能力，那么最好通过配置 test 来将该 client 模块从懒编译模块中排除出去。

如果不排除掉，并且开启 entry 的懒编译，该 client 在第一次访问页面时不会被编译，因此需要一次额外的刷新才能让其真正生效。

```js title="rspack.config.mjs"
import { rspack } from '@rspack/core';

const options = {
  lazyCompilation: {
    test(module) {
      const isMyClient = module.nameForCondition().endsWith('dev-client.js');
      // 让 dev-client.js 不被懒编译
      return !isMyClient;
    },
  },
};
const compiler = rspack(options);

new compiler.rspack.EntryPlugin(compiler.context, 'dev-client.js', {
  // name: undefined 代表这是全局 entry，会插入到每一个 entry 前
  name: undefined,
}).apply(compiler);
```
